home *** CD-ROM | disk | FTP | other *** search
/ Aminet 35 / Aminet 35 (2000)(Schatztruhe)[!][Feb 2000].iso / Aminet / game / shoot / ADescentSrc.lha / descent / main / gamesave.c < prev    next >
C/C++ Source or Header  |  1998-08-08  |  50KB  |  1,948 lines

  1. /*
  2. THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
  3. SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
  4. END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
  5. ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
  6. IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
  7. SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
  8. FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
  9. CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
  10. AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.  
  11. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
  12. */
  13. /*
  14.  * $Source: /usr/CVS/descent/main/gamesave.c,v $
  15.  * $Revision: 1.3 $
  16.  * $Author: nobody $
  17.  * $Date: 1998/08/08 15:43:59 $
  18.  * 
  19.  * Save game information
  20.  * 
  21.  * $Log: gamesave.c,v $
  22.  * Revision 1.3  1998/08/08 15:43:59  nobody
  23.  * Activated the Editior
  24.  *
  25.  * Revision 1.2  1998/03/13 23:52:01  tfrieden
  26.  * various changes with sound, joystick, shareware, notwork
  27.  *
  28.  * Revision 1.1.1.1  1998/03/03 15:12:20  nobody
  29.  * reimport after crash from backup
  30.  *
  31.  * Revision 1.1.1.1  1998/02/13  20:20:45  hfrieden
  32.  * Initial Import
  33.  */
  34.  
  35. #pragma off (unreferenced)
  36. static char rcsid[] = "$Id: gamesave.c,v 1.3 1998/08/08 15:43:59 nobody Exp $";
  37. #pragma on (unreferenced)
  38.  
  39.  
  40. #include <stdio.h>
  41. #include <stdlib.h>
  42. #include <math.h>
  43. #include <string.h>
  44.  
  45. #include "mono.h"
  46. #include "key.h"
  47. #include "gr.h"
  48. #include "palette.h"
  49. #include "newmenu.h"
  50.  
  51. #include "inferno.h"
  52. #ifdef EDITOR
  53. #include "editor/editor.h"
  54. #endif
  55. #include "error.h"
  56. #include "object.h"
  57. #include "game.h"
  58. #include "screens.h"
  59. #include "wall.h"
  60. #include "gamemine.h"
  61. #include "robot.h"
  62.  
  63.  
  64. #include "cflib.h"
  65. #include "cfile.h"
  66. #include "bm.h"
  67. #include "menu.h"
  68. #include "switch.h"
  69. #include "fuelcen.h"
  70. #include "powerup.h"
  71. #include "hostage.h"
  72. #include "weapon.h"
  73. #include "newdemo.h"
  74. #include "gameseq.h"
  75. #include "automap.h"
  76. #include "polyobj.h"
  77. #include "text.h"
  78. #include "gamefont.h"
  79. #include "gamesave.h"
  80.  
  81. #ifdef EDITOR
  82. char *Shareware_level_names[NUM_SHAREWARE_LEVELS] = {
  83.     "level01.sdl",
  84.     "level02.sdl",
  85.     "level03.sdl",
  86.     "level04.sdl",
  87.     "level05.sdl",
  88.     "level06.sdl",
  89.     "level07.sdl"
  90. };
  91.  
  92. #if 0
  93. char *Shareware_level_names[NUM_SHAREWARE_LEVELS] = {
  94.     "level01.rdl",
  95.     "level02.rdl",
  96.     "level03.rdl",
  97.     "level04.rdl",
  98.     "level05.rdl",
  99.     "level06.rdl",
  100.     "level07.rdl"
  101. };
  102. #endif
  103.  
  104.  
  105. char *Registered_level_names[NUM_REGISTERED_LEVELS] = {
  106.     "level08.rdl",
  107.     "level09.rdl",
  108.     "level10.rdl",
  109.     "level11.rdl",
  110.     "level12.rdl",
  111.     "level13.rdl",
  112.     "level14.rdl",
  113.     "level15.rdl",
  114.     "level16.rdl",
  115.     "level17.rdl",
  116.     "level18.rdl",
  117.     "level19.rdl",
  118.     "level20.rdl",
  119.     "level21.rdl",
  120.     "level22.rdl",
  121.     "level23.rdl",
  122.     "level24.rdl",
  123.     "level25.rdl",
  124.     "level26.rdl",
  125.     "level27.rdl",
  126.     "levels1.rdl",
  127.     "levels2.rdl",
  128.     "levels3.rdl"
  129. };
  130. #endif
  131.  
  132. extern int UseShareware;
  133. char Gamesave_current_filename[128];
  134.  
  135. #define GAME_VERSION                    25
  136. #define GAME_COMPATIBLE_VERSION 22
  137.  
  138. #define MENU_CURSOR_X_MIN           MENU_X
  139. #define MENU_CURSOR_X_MAX           MENU_X+6
  140.  
  141. #define HOSTAGE_DATA_VERSION    0
  142.  
  143. //Start old wall structures
  144.  
  145. typedef struct v16_wall {
  146.     byte  type;                 // What kind of special wall.
  147.     byte    flags;              // Flags for the wall.      
  148.     fix   hps;                  // "Hit points" of the wall. 
  149.     byte    trigger;                // Which trigger is associated with the wall.
  150.     byte    clip_num;           // Which    animation associated with the wall. 
  151.     byte    keys;
  152.     } v16_wall;
  153.  
  154. typedef struct v19_wall {
  155.     int segnum,sidenum; // Seg & side for this wall
  156.     byte    type;               // What kind of special wall.
  157.     byte    flags;              // Flags for the wall.      
  158.     fix   hps;                  // "Hit points" of the wall. 
  159.     byte    trigger;                // Which trigger is associated with the wall.
  160.     byte    clip_num;           // Which    animation associated with the wall. 
  161.     byte    keys;
  162.     int linked_wall;        // number of linked wall
  163.     } v19_wall;
  164.  
  165. typedef struct v19_door {
  166.     int     n_parts;                    // for linked walls
  167.     short   seg[2];                     // Segment pointer of door.
  168.     short   side[2];                    // Side number of door.
  169.     short   type[2];                    // What kind of door animation.
  170.     fix         open;                       //  How long it has been open.
  171. } v19_door;
  172.  
  173. //End old wall structures
  174.  
  175. struct {
  176.     ushort  fileinfo_signature;
  177.     ushort  fileinfo_version;
  178.     int     fileinfo_sizeof;
  179. } game_top_fileinfo;    // Should be same as first two fields below...
  180.  
  181. struct {
  182.     ushort  fileinfo_signature;
  183.     ushort  fileinfo_version;
  184.     int     fileinfo_sizeof;
  185.     char        mine_filename[15];
  186.     int     level;
  187.     int     player_offset;              // Player info
  188.     int     player_sizeof;
  189.     int     object_offset;              // Object info
  190.     int     object_howmany;     
  191.     int     object_sizeof;  
  192.     int     walls_offset;
  193.     int     walls_howmany;
  194.     int     walls_sizeof;
  195.     int     doors_offset;
  196.     int     doors_howmany;
  197.     int     doors_sizeof;
  198.     int     triggers_offset;
  199.     int     triggers_howmany;
  200.     int     triggers_sizeof;
  201.     int     links_offset;
  202.     int     links_howmany;
  203.     int     links_sizeof;
  204.     int     control_offset;
  205.     int     control_howmany;
  206.     int     control_sizeof;
  207.     int     matcen_offset;
  208.     int     matcen_howmany;
  209.     int     matcen_sizeof;
  210. } game_fileinfo;
  211.  
  212. #ifdef EDITOR
  213. extern char mine_filename[];
  214. extern int save_mine_data_compiled(FILE * SaveFile);
  215. //--unused-- #else
  216. //--unused-- char mine_filename[128];
  217. #endif
  218.  
  219. int Gamesave_num_org_robots = 0;
  220. //--unused-- grs_bitmap * Gamesave_saved_bitmap = NULL;
  221.  
  222. #ifdef EDITOR
  223. //  Return true if this level has a name of the form "level??"
  224. //  Note that a pathspec can appear at the beginning of the filename.
  225. int is_real_level(char *filename)
  226. {
  227.     int len = strlen(filename);
  228.  
  229.     if (len < 6)
  230.         return 0;
  231.  
  232.     //mprintf((0, "String = [%s]\n", &filename[len-11]));
  233.     return !strnicmp(&filename[len-11], "level", 5);
  234.  
  235. }
  236.  
  237. void convert_name_to_CDL( char *dest, char *src )
  238. {
  239.     int i;
  240.  
  241.     strcpy (dest, src);
  242.  
  243.     if (UseShareware) {
  244.         for (i=1; i<strlen(dest); i++ )
  245.         {
  246.             if (dest[i]=='.'||dest[i]==' '||dest[i]==0)
  247.             {
  248.                 dest[i]='.';
  249.                 dest[i+1]='S';
  250.                 dest[i+2]= 'D';
  251.                 dest[i+3]= 'L';
  252.                 dest[i+4]=0;
  253.                 return;
  254.             }
  255.         }
  256.  
  257.         if (i < 123)
  258.         {
  259.             dest[i]='.';
  260.             dest[i+1]='S';
  261.             dest[i+2]= 'D';
  262.             dest[i+3]= 'L';
  263.             dest[i+4]=0;
  264.             return;
  265.         }
  266.     } else {
  267.         for (i=1; i<strlen(dest); i++ )
  268.         {
  269.             if (dest[i]=='.'||dest[i]==' '||dest[i]==0)
  270.             {
  271.                 dest[i]='.';
  272.                 dest[i+1]='R';
  273.                 dest[i+2]= 'D';
  274.                 dest[i+3]= 'L';
  275.                 dest[i+4]=0;
  276.                 return;
  277.             }
  278.         }
  279.  
  280.         if (i < 123)
  281.         {
  282.             dest[i]='.';
  283.             dest[i+1]='R';
  284.             dest[i+2]= 'D';
  285.             dest[i+3]= 'L';
  286.             dest[i+4]=0;
  287.             return;
  288.         }
  289.     }
  290.  
  291. }
  292. #endif
  293.  
  294. void convert_name_to_LVL( char *dest, char *src )
  295. {
  296.     int i;
  297.  
  298.     strcpy (dest, src);
  299.  
  300.     for (i=1; i<strlen(dest); i++ )
  301.     {
  302.         if (dest[i]=='.'||dest[i]==' '||dest[i]==0)
  303.         {
  304.             dest[i]='.';
  305.             dest[i+1]='L';
  306.             dest[i+2]= 'V';
  307.             dest[i+3]= 'L';
  308.             dest[i+4]=0;
  309.             return;
  310.         }
  311.     }
  312.  
  313.     if (i < 123)
  314.     {
  315.         dest[i]='.';
  316.         dest[i+1]='L';
  317.         dest[i+2]= 'V';
  318.         dest[i+3]= 'L';
  319.         dest[i+4]=0;
  320.         return;
  321.     }
  322. }
  323.  
  324. //--unused-- vms_angvec zero_angles={0,0,0};
  325.  
  326. #define vm_angvec_zero(v) do {(v)->p=(v)->b=(v)->h=0;} while (0)
  327.  
  328. int Gamesave_num_players=0;
  329.  
  330. int N_save_pof_names=25;
  331. char Save_pof_names[MAX_POLYGON_MODELS][13];
  332.  
  333. check_and_fix_matrix(vms_matrix *m);
  334.  
  335. void verify_object( object * obj )  {
  336.  
  337.     obj->lifeleft = IMMORTAL_TIME;      //all loaded object are immortal, for now
  338.  
  339.     if ( obj->type == OBJ_ROBOT )   {
  340.         Gamesave_num_org_robots++;
  341.  
  342.         // Make sure valid id...
  343.         if ( obj->id >= N_robot_types )
  344.             obj->id = obj->id % N_robot_types;
  345.  
  346.         // Make sure model number & size are correct...     
  347.         if ( obj->render_type == RT_POLYOBJ ) {
  348.             obj->rtype.pobj_info.model_num = Robot_info[obj->id].model_num;
  349.             obj->size = Polygon_models[obj->rtype.pobj_info.model_num].rad;
  350.  
  351.             //@@if (obj->control_type==CT_AI && Robot_info[obj->id].attack_type)
  352.             //@@    obj->size = obj->size*3/4;
  353.         }
  354.  
  355.         if (obj->movement_type == MT_PHYSICS) {
  356.             obj->mtype.phys_info.mass = Robot_info[obj->id].mass;
  357.             obj->mtype.phys_info.drag = Robot_info[obj->id].drag;
  358.         }
  359.     }
  360.     else {      //Robots taken care of above
  361.  
  362.         if ( obj->render_type == RT_POLYOBJ ) {
  363.             int i;
  364.             char *name = Save_pof_names[obj->rtype.pobj_info.model_num];
  365.  
  366.             for (i=0;i<N_polygon_models;i++)
  367.                 if (!stricmp(Pof_names[i],name)) {      //found it! 
  368.                     // mprintf((0,"Mapping <%s> to %d (was %d)\n",name,i,obj->rtype.pobj_info.model_num));
  369.                     obj->rtype.pobj_info.model_num = i;
  370.                     break;
  371.                 }
  372.         }
  373.     }
  374.  
  375.     if ( obj->type == OBJ_POWERUP ) {
  376.         if ( obj->id >= N_powerup_types )   {
  377.             obj->id = 0;
  378.             Assert( obj->render_type != RT_POLYOBJ );
  379.         }
  380.         obj->control_type = CT_POWERUP;
  381.  
  382.         obj->size = Powerup_info[obj->id].size;
  383.     }
  384.  
  385.     //if ( obj->type == OBJ_HOSTAGE )   {
  386.     //  if ( obj->id >= N_hostage_types )   {
  387.     //      obj->id = 0;
  388.     //      Assert( obj->render_type == RT_POLYOBJ );
  389.     //  }
  390.     //}
  391.  
  392.     if ( obj->type == OBJ_WEAPON )  {
  393.         if ( obj->id >= N_weapon_types )    {
  394.             obj->id = 0;
  395.             Assert( obj->render_type != RT_POLYOBJ );
  396.         }
  397.     }
  398.  
  399.     if ( obj->type == OBJ_CNTRLCEN )    {
  400.         int i;
  401.  
  402.         obj->render_type = RT_POLYOBJ;
  403.         obj->control_type = CT_CNTRLCEN;
  404.  
  405.         // Make model number is correct...  
  406.         for (i=0; i<Num_total_object_types; i++ )   
  407.             if ( ObjType[i] == OL_CONTROL_CENTER )      {
  408.                 obj->rtype.pobj_info.model_num = ObjId[i];
  409.                 obj->shields = ObjStrength[i];
  410.                 break;      
  411.             }
  412.     }
  413.  
  414.     if ( obj->type == OBJ_PLAYER )  {
  415.         //int i;
  416.  
  417.         //Assert(obj == Player);
  418.  
  419.         if ( obj == ConsoleObject )     
  420.             init_player_object();
  421.         else
  422.             if (obj->render_type == RT_POLYOBJ) //recover from Matt's pof file matchup bug
  423.                 obj->rtype.pobj_info.model_num = Player_ship->model_num;
  424.  
  425.         //Make sure orient matrix is orthogonal
  426.         check_and_fix_matrix(&obj->orient);
  427.  
  428.         obj->id = Gamesave_num_players++;
  429.     }
  430.  
  431.     if (obj->type == OBJ_HOSTAGE) {
  432.  
  433.         if (obj->id > N_hostage_types)
  434.             obj->id = 0;
  435.  
  436.         obj->render_type = RT_HOSTAGE;
  437.         obj->control_type = CT_POWERUP;
  438.         //obj->vclip_info.vclip_num = Hostage_vclip_num[Hostages[obj->id].type];
  439.         //obj->vclip_info.frametime = Vclip[obj->vclip_info.vclip_num].frame_time;
  440.         //obj->vclip_info.framenum = 0;
  441.     }
  442.  
  443. }
  444.  
  445. static int read_int(CFILE *file)
  446. {
  447.     int i;
  448.  
  449.     if (cfread( &i, sizeof(i), 1, file) != 1)
  450.         Error( "Error reading int in gamesave.c" );
  451.  
  452.     return swapint(i);
  453. }
  454.  
  455. static fix read_fix(CFILE *file)
  456. {
  457.     fix f;
  458.  
  459.     if (cfread( &f, sizeof(f), 1, file) != 1)
  460.         Error( "Error reading fix in gamesave.c" );
  461.  
  462.     return (fix)swapint(f);
  463. }
  464.  
  465. static short read_short(CFILE *file)
  466. {
  467.     short s;
  468.  
  469.     if (cfread( &s, sizeof(s), 1, file) != 1)
  470.         Error( "Error reading short in gamesave.c" );
  471.  
  472.     return swapshort(s);
  473. }
  474.  
  475. static short read_fixang(CFILE *file)
  476. {
  477.     fixang f;
  478.  
  479.     if (cfread( &f, sizeof(f), 1, file) != 1)
  480.         Error( "Error reading fixang in gamesave.c" );
  481.  
  482.     return (fixang)(swapshort(f));
  483. }
  484.  
  485. static byte read_byte(CFILE *file)
  486. {
  487.     byte b;
  488.  
  489.     if (cfread( &b, sizeof(b), 1, file) != 1)
  490.         Error( "Error reading byte in gamesave.c" );
  491.  
  492.     return b;
  493. }
  494.  
  495. static void read_vector(vms_vector *v,CFILE *file)
  496. {
  497.     v->x = read_fix(file);
  498.     v->y = read_fix(file);
  499.     v->z = read_fix(file);
  500. }
  501.  
  502. static void read_matrix(vms_matrix *m,CFILE *file)
  503. {
  504.     read_vector(&m->rvec,file);
  505.     read_vector(&m->uvec,file);
  506.     read_vector(&m->fvec,file);
  507. }
  508.  
  509. static void read_angvec(vms_angvec *v,CFILE *file)
  510. {
  511.     v->p = read_fixang(file);
  512.     v->b = read_fixang(file);
  513.     v->h = read_fixang(file);
  514. }
  515.  
  516. //static gs_skip(int len,CFILE *file)
  517. //{
  518. //
  519. //  cfseek(file,len,SEEK_CUR);
  520. //}
  521.  
  522. #ifdef EDITOR
  523. static void gs_write_int(int i,FILE *file)
  524. {
  525.     i = swapint(i);
  526.     if (fwrite( &i, sizeof(i), 1, file) != 1)
  527.         Error( "Error reading int in gamesave.c" );
  528.  
  529. }
  530.  
  531. static void gs_write_fix(fix f,FILE *file)
  532. {
  533.     f = swapint(f);
  534.     if (fwrite( &f, sizeof(f), 1, file) != 1)
  535.         Error( "Error reading fix in gamesave.c" );
  536.  
  537. }
  538.  
  539. static void gs_write_short(short s,FILE *file)
  540. {
  541.     s = swapshort(s);
  542.     if (fwrite( &s, sizeof(s), 1, file) != 1)
  543.         Error( "Error reading short in gamesave.c" );
  544.  
  545. }
  546.  
  547. static void gs_write_fixang(fixang f,FILE *file)
  548. {
  549.     f = (fixang)swapshort(f);
  550.     if (fwrite( &f, sizeof(f), 1, file) != 1)
  551.         Error( "Error reading fixang in gamesave.c" );
  552.  
  553. }
  554.  
  555. static void gs_write_byte(byte b,FILE *file)
  556. {
  557.     if (fwrite( &b, sizeof(b), 1, file) != 1)
  558.         Error( "Error reading byte in gamesave.c" );
  559.  
  560. }
  561.  
  562. static void gr_write_vector(vms_vector *v,FILE *file)
  563. {
  564.     gs_write_fix(v->x,file);
  565.     gs_write_fix(v->y,file);
  566.     gs_write_fix(v->z,file);
  567. }
  568.  
  569. static void gs_write_matrix(vms_matrix *m,FILE *file)
  570. {
  571.     gr_write_vector(&m->rvec,file);
  572.     gr_write_vector(&m->uvec,file);
  573.     gr_write_vector(&m->fvec,file);
  574. }
  575.  
  576. static void gs_write_angvec(vms_angvec *v,FILE *file)
  577. {
  578.     gs_write_fixang(v->p,file);
  579.     gs_write_fixang(v->b,file);
  580.     gs_write_fixang(v->h,file);
  581. }
  582.  
  583. #endif
  584.  
  585. //reads one object of the given version from the given file
  586. read_object(object *obj,CFILE *f,int version)
  587. {
  588.     obj->type               = read_byte(f);
  589.     obj->id                 = read_byte(f);
  590.  
  591.     obj->control_type       = read_byte(f);
  592.     obj->movement_type  = read_byte(f);
  593.     obj->render_type        = read_byte(f);
  594.     obj->flags              = read_byte(f);
  595.  
  596.     obj->segnum             = read_short(f);
  597.     obj->attached_obj       = -1;
  598.  
  599.     read_vector(&obj->pos,f);
  600.     read_matrix(&obj->orient,f);
  601.  
  602.     obj->size               = read_fix(f);
  603.     obj->shields            = read_fix(f);
  604.  
  605.     read_vector(&obj->last_pos,f);
  606.  
  607.     obj->contains_type  = read_byte(f);
  608.     obj->contains_id        = read_byte(f);
  609.     obj->contains_count = read_byte(f);
  610.  
  611.     switch (obj->movement_type) {
  612.  
  613.         case MT_PHYSICS:
  614.  
  615.             read_vector(&obj->mtype.phys_info.velocity,f);
  616.             read_vector(&obj->mtype.phys_info.thrust,f);
  617.  
  618.             obj->mtype.phys_info.mass       = read_fix(f);
  619.             obj->mtype.phys_info.drag       = read_fix(f);
  620.             obj->mtype.phys_info.brakes = read_fix(f);
  621.  
  622.             read_vector(&obj->mtype.phys_info.rotvel,f);
  623.             read_vector(&obj->mtype.phys_info.rotthrust,f);
  624.  
  625.             obj->mtype.phys_info.turnroll   = read_fixang(f);
  626.             obj->mtype.phys_info.flags      = read_short(f);
  627.  
  628.             break;
  629.  
  630.         case MT_SPINNING:
  631.  
  632.             read_vector(&obj->mtype.spin_rate,f);
  633.             break;
  634.  
  635.         case MT_NONE:
  636.             break;
  637.  
  638.         default:
  639.             Int3();
  640.     }
  641.  
  642.     switch (obj->control_type) {
  643.  
  644.         case CT_AI: {
  645.             int i;
  646.  
  647.             obj->ctype.ai_info.behavior             = read_byte(f);
  648.  
  649.             for (i=0;i<MAX_AI_FLAGS;i++)
  650.                 obj->ctype.ai_info.flags[i]         = read_byte(f);
  651.  
  652.             obj->ctype.ai_info.hide_segment         = read_short(f);
  653.             obj->ctype.ai_info.hide_index               = read_short(f);
  654.             obj->ctype.ai_info.path_length          = read_short(f);
  655.             obj->ctype.ai_info.cur_path_index       = read_short(f);
  656.  
  657.             obj->ctype.ai_info.follow_path_start_seg    = read_short(f);
  658.             obj->ctype.ai_info.follow_path_end_seg      = read_short(f);
  659.  
  660.             break;
  661.         }
  662.  
  663.         case CT_EXPLOSION:
  664.  
  665.             obj->ctype.expl_info.spawn_time     = read_fix(f);
  666.             obj->ctype.expl_info.delete_time        = read_fix(f);
  667.             obj->ctype.expl_info.delete_objnum  = read_short(f);
  668.             obj->ctype.expl_info.next_attach = obj->ctype.expl_info.prev_attach = obj->ctype.expl_info.attach_parent = -1;
  669.  
  670.             break;
  671.  
  672.         case CT_WEAPON:
  673.  
  674.             //do I really need to read these?  Are they even saved to disk?
  675.  
  676.             obj->ctype.laser_info.parent_type       = read_short(f);
  677.             obj->ctype.laser_info.parent_num            = read_short(f);
  678.             obj->ctype.laser_info.parent_signature  = read_int(f);
  679.  
  680.             break;
  681.  
  682.         case CT_LIGHT:
  683.  
  684.             obj->ctype.light_info.intensity = read_fix(f);
  685.             break;
  686.  
  687.         case CT_POWERUP:
  688.  
  689.             if (version >= 25)
  690.                 obj->ctype.powerup_info.count = read_int(f);
  691.             else
  692.                 obj->ctype.powerup_info.count = 1;
  693.  
  694.             if (obj->id == POW_VULCAN_WEAPON)
  695.                     obj->ctype.powerup_info.count = VULCAN_WEAPON_AMMO_AMOUNT;
  696.  
  697.             break;
  698.  
  699.  
  700.         case CT_NONE:
  701.         case CT_FLYING:
  702.         case CT_DEBRIS:
  703.             break;
  704.  
  705.         case CT_SLEW:       //the player is generally saved as slew
  706.             break;
  707.  
  708.         case CT_CNTRLCEN:
  709.             break;
  710.  
  711.         case CT_MORPH:
  712.         case CT_FLYTHROUGH:
  713.         case CT_REPAIRCEN:
  714.         default:
  715.             Int3();
  716.     
  717.     }
  718.  
  719.     switch (obj->render_type) {
  720.  
  721.         case RT_NONE:
  722.             break;
  723.  
  724.         case RT_MORPH:
  725.         case RT_POLYOBJ: {
  726.             int i,tmo;
  727.  
  728.             obj->rtype.pobj_info.model_num      = read_int(f);
  729.  
  730.             for (i=0;i<MAX_SUBMODELS;i++)
  731.                 read_angvec(&obj->rtype.pobj_info.anim_angles[i],f);
  732.  
  733.             obj->rtype.pobj_info.subobj_flags   = read_int(f);
  734.  
  735.             tmo = read_int(f);
  736.  
  737.             #ifndef EDITOR
  738.             obj->rtype.pobj_info.tmap_override  = tmo;
  739.             #else
  740.             if (tmo==-1)
  741.                 obj->rtype.pobj_info.tmap_override  = -1;
  742.             else {
  743.                 int xlated_tmo = tmap_xlate_table[tmo];
  744.                 if (xlated_tmo < 0) {
  745.                     mprintf( (0, "Couldn't find texture for demo object, model_num = %d\n", obj->rtype.pobj_info.model_num));
  746.                     Int3();
  747.                     xlated_tmo = 0;
  748.                 }
  749.                 obj->rtype.pobj_info.tmap_override  = xlated_tmo;
  750.             }
  751.             #endif
  752.  
  753.             obj->rtype.pobj_info.alt_textures   = 0;
  754.  
  755.             break;
  756.         }
  757.  
  758.         case RT_WEAPON_VCLIP:
  759.         case RT_HOSTAGE:
  760.         case RT_POWERUP:
  761.         case RT_FIREBALL:
  762.  
  763.             obj->rtype.vclip_info.vclip_num = read_int(f);
  764.             obj->rtype.vclip_info.frametime = read_fix(f);
  765.             obj->rtype.vclip_info.framenum  = read_byte(f);
  766.  
  767.             break;
  768.  
  769.         case RT_LASER:
  770.             break;
  771.  
  772.         default:
  773.             Int3();
  774.  
  775.     }
  776.  
  777. }
  778.  
  779. #ifdef EDITOR
  780.  
  781. //writes one object to the given file
  782. write_object(object *obj,FILE *f)
  783. {
  784.     gs_write_byte(obj->type,f);
  785.     gs_write_byte(obj->id,f);
  786.  
  787.     gs_write_byte(obj->control_type,f);
  788.     gs_write_byte(obj->movement_type,f);
  789.     gs_write_byte(obj->render_type,f);
  790.     gs_write_byte(obj->flags,f);
  791.  
  792.     gs_write_short(obj->segnum,f);
  793.  
  794.     gr_write_vector(&obj->pos,f);
  795.     gs_write_matrix(&obj->orient,f);
  796.  
  797.     gs_write_fix(obj->size,f);
  798.     gs_write_fix(obj->shields,f);
  799.  
  800.     gr_write_vector(&obj->last_pos,f);
  801.  
  802.     gs_write_byte(obj->contains_type,f);
  803.     gs_write_byte(obj->contains_id,f);
  804.     gs_write_byte(obj->contains_count,f);
  805.  
  806.     switch (obj->movement_type) {
  807.  
  808.         case MT_PHYSICS:
  809.  
  810.             gr_write_vector(&obj->mtype.phys_info.velocity,f);
  811.             gr_write_vector(&obj->mtype.phys_info.thrust,f);
  812.  
  813.             gs_write_fix(obj->mtype.phys_info.mass,f);
  814.             gs_write_fix(obj->mtype.phys_info.drag,f);
  815.             gs_write_fix(obj->mtype.phys_info.brakes,f);
  816.  
  817.             gr_write_vector(&obj->mtype.phys_info.rotvel,f);
  818.             gr_write_vector(&obj->mtype.phys_info.rotthrust,f);
  819.  
  820.             gs_write_fixang(obj->mtype.phys_info.turnroll,f);
  821.             gs_write_short(obj->mtype.phys_info.flags,f);
  822.  
  823.             break;
  824.  
  825.         case MT_SPINNING:
  826.  
  827.             gr_write_vector(&obj->mtype.spin_rate,f);
  828.             break;
  829.  
  830.         case MT_NONE:
  831.             break;
  832.  
  833.         default:
  834.             Int3();
  835.     }
  836.  
  837.     switch (obj->control_type) {
  838.  
  839.         case CT_AI: {
  840.             int i;
  841.  
  842.             gs_write_byte(obj->ctype.ai_info.behavior,f);
  843.  
  844.             for (i=0;i<MAX_AI_FLAGS;i++)
  845.                 gs_write_byte(obj->ctype.ai_info.flags[i],f);
  846.  
  847.             gs_write_short(obj->ctype.ai_info.hide_segment,f);
  848.             gs_write_short(obj->ctype.ai_info.hide_index,f);
  849.             gs_write_short(obj->ctype.ai_info.path_length,f);
  850.             gs_write_short(obj->ctype.ai_info.cur_path_index,f);
  851.  
  852.             gs_write_short(obj->ctype.ai_info.follow_path_start_seg,f);
  853.             gs_write_short(obj->ctype.ai_info.follow_path_end_seg,f);
  854.  
  855.             break;
  856.         }
  857.  
  858.         case CT_EXPLOSION:
  859.  
  860.             gs_write_fix(obj->ctype.expl_info.spawn_time,f);
  861.             gs_write_fix(obj->ctype.expl_info.delete_time,f);
  862.             gs_write_short(obj->ctype.expl_info.delete_objnum,f);
  863.  
  864.             break;
  865.  
  866.         case CT_WEAPON:
  867.  
  868.             //do I really need to write these objects?
  869.  
  870.             gs_write_short(obj->ctype.laser_info.parent_type,f);
  871.             gs_write_short(obj->ctype.laser_info.parent_num,f);
  872.             gs_write_int(obj->ctype.laser_info.parent_signature,f);
  873.  
  874.             break;
  875.  
  876.             break;
  877.  
  878.         case CT_LIGHT:
  879.  
  880.             gs_write_fix(obj->ctype.light_info.intensity,f);
  881.             break;
  882.  
  883.         case CT_POWERUP:
  884.  
  885.             gs_write_int(obj->ctype.powerup_info.count,f);
  886.             break;
  887.  
  888.         case CT_NONE:
  889.         case CT_FLYING:
  890.         case CT_DEBRIS:
  891.             break;
  892.  
  893.         case CT_SLEW:       //the player is generally saved as slew
  894.             break;
  895.  
  896.         case CT_CNTRLCEN:
  897.             break;          //control center object.
  898.  
  899.         case CT_MORPH:
  900.         case CT_REPAIRCEN:
  901.         case CT_FLYTHROUGH:
  902.         default:
  903.             Int3();
  904.     
  905.     }
  906.  
  907.     switch (obj->render_type) {
  908.  
  909.         case RT_NONE:
  910.             break;
  911.  
  912.         case RT_MORPH:
  913.         case RT_POLYOBJ: {
  914.             int i;
  915.  
  916.             gs_write_int(obj->rtype.pobj_info.model_num,f);
  917.  
  918.             for (i=0;i<MAX_SUBMODELS;i++)
  919.                 gs_write_angvec(&obj->rtype.pobj_info.anim_angles[i],f);
  920.  
  921.             gs_write_int(obj->rtype.pobj_info.subobj_flags,f);
  922.  
  923.             gs_write_int(obj->rtype.pobj_info.tmap_override,f);
  924.  
  925.             break;
  926.         }
  927.  
  928.         case RT_WEAPON_VCLIP:
  929.         case RT_HOSTAGE:
  930.         case RT_POWERUP:
  931.         case RT_FIREBALL:
  932.  
  933.             gs_write_int(obj->rtype.vclip_info.vclip_num,f);
  934.             gs_write_fix(obj->rtype.vclip_info.frametime,f);
  935.             gs_write_byte(obj->rtype.vclip_info.framenum,f);
  936.  
  937.             break;
  938.  
  939.         case RT_LASER:
  940.             break;
  941.  
  942.         default:
  943.             Int3();
  944.  
  945.     }
  946.  
  947. }
  948. #endif
  949.  
  950. // -----------------------------------------------------------------------------
  951. // Load game 
  952. // Loads all the relevant data for a level.
  953. // If level != -1, it loads the filename with extension changed to .min
  954. // Otherwise it loads the appropriate level mine.
  955. // returns 0=everything ok, 1=old version, -1=error
  956. load_game_data(CFILE *LoadFile)
  957. {
  958.     int i,j;
  959.     int start_offset;
  960.  
  961.     start_offset = cftell(LoadFile);
  962.  
  963.     //===================== READ FILE INFO ========================
  964.  
  965.     // Set default values
  966.     game_fileinfo.level                 =   -1;
  967.     game_fileinfo.player_offset     =   -1;
  968.     game_fileinfo.player_sizeof     =   sizeof(player);
  969.     game_fileinfo.object_offset     =   -1;
  970.     game_fileinfo.object_howmany        =   0;
  971.     game_fileinfo.object_sizeof     =   sizeof(object);  
  972.     game_fileinfo.walls_offset          =   -1;
  973.     game_fileinfo.walls_howmany     =   0;
  974.     game_fileinfo.walls_sizeof          =   sizeof(wall);  
  975.     game_fileinfo.doors_offset          =   -1;
  976.     game_fileinfo.doors_howmany     =   0;
  977.     game_fileinfo.doors_sizeof          =   sizeof(active_door);  
  978.     game_fileinfo.triggers_offset       =   -1;
  979.     game_fileinfo.triggers_howmany  =   0;
  980.     game_fileinfo.triggers_sizeof       =   sizeof(trigger);  
  981.     game_fileinfo.control_offset        =   -1;
  982.     game_fileinfo.control_howmany       =   0;
  983.     game_fileinfo.control_sizeof        =   sizeof(control_center_triggers);
  984.     game_fileinfo.matcen_offset     =   -1;
  985.     game_fileinfo.matcen_howmany        =   0;
  986.     game_fileinfo.matcen_sizeof     =   sizeof(matcen_info);
  987.  
  988.     // Read in game_top_fileinfo to get size of saved fileinfo.
  989.  
  990.     if (cfseek( LoadFile, start_offset, SEEK_SET )) 
  991.         Error( "Error seeking in gamesave.c" ); 
  992.  
  993.     //if (cfread( &game_top_fileinfo, sizeof(game_top_fileinfo), 1, LoadFile) != 1)
  994.     //    Error( "Error reading game_top_fileinfo in gamesave.c" );
  995.     game_top_fileinfo.fileinfo_signature = read_short(LoadFile);
  996.     game_top_fileinfo.fileinfo_version = read_short(LoadFile);
  997.     game_top_fileinfo.fileinfo_sizeof = read_int(LoadFile);
  998.  
  999.  
  1000.     // Check signature
  1001.     if (game_top_fileinfo.fileinfo_signature != 0x6705)
  1002.         return -1;
  1003.  
  1004.     // Check version number
  1005.     if (game_top_fileinfo.fileinfo_version < GAME_COMPATIBLE_VERSION )
  1006.         return -1;
  1007.  
  1008.     // Now, Read in the fileinfo
  1009.     if (cfseek( LoadFile, start_offset, SEEK_SET )) 
  1010.         Error( "Error seeking to game_fileinfo in gamesave.c" );
  1011.  
  1012.     game_fileinfo.fileinfo_signature = read_short(LoadFile);
  1013.  
  1014.     game_fileinfo.fileinfo_version = read_short(LoadFile);
  1015.     game_fileinfo.fileinfo_sizeof = read_int(LoadFile);
  1016.     for(i=0; i<15; i++)
  1017.         game_fileinfo.mine_filename[i] = read_byte(LoadFile);
  1018.     game_fileinfo.level = read_int(LoadFile);
  1019.     game_fileinfo.player_offset = read_int(LoadFile);               // Player info
  1020.     game_fileinfo.player_sizeof = read_int(LoadFile);
  1021.     game_fileinfo.object_offset = read_int(LoadFile);               // Object info
  1022.     game_fileinfo.object_howmany = read_int(LoadFile);      
  1023.     game_fileinfo.object_sizeof = read_int(LoadFile);  
  1024.     game_fileinfo.walls_offset = read_int(LoadFile);
  1025.     game_fileinfo.walls_howmany = read_int(LoadFile);
  1026.     game_fileinfo.walls_sizeof = read_int(LoadFile);
  1027.     game_fileinfo.doors_offset = read_int(LoadFile);
  1028.     game_fileinfo.doors_howmany = read_int(LoadFile);
  1029.     game_fileinfo.doors_sizeof = read_int(LoadFile);
  1030.     game_fileinfo.triggers_offset = read_int(LoadFile);
  1031.     game_fileinfo.triggers_howmany = read_int(LoadFile);
  1032.     game_fileinfo.triggers_sizeof = read_int(LoadFile);
  1033.     game_fileinfo.links_offset = read_int(LoadFile);
  1034.     game_fileinfo.links_howmany = read_int(LoadFile);
  1035.     game_fileinfo.links_sizeof = read_int(LoadFile);
  1036.     game_fileinfo.control_offset = read_int(LoadFile);
  1037.     game_fileinfo.control_howmany = read_int(LoadFile);
  1038.     game_fileinfo.control_sizeof = read_int(LoadFile);
  1039.     game_fileinfo.matcen_offset = read_int(LoadFile);
  1040.     game_fileinfo.matcen_howmany = read_int(LoadFile);
  1041.     game_fileinfo.matcen_sizeof = read_int(LoadFile);
  1042.  
  1043. //  if (cfread( &game_fileinfo, game_top_fileinfo.fileinfo_sizeof, 1, LoadFile )!=1)
  1044. //      Error( "Error reading game_fileinfo in gamesave.c" );
  1045.  
  1046.     if (game_top_fileinfo.fileinfo_version >= 14) { //load mine filename
  1047.         char *p=Current_level_name;
  1048.         //must do read one char at a time, since no cfgets()
  1049.         do *p = cfgetc(LoadFile); while (*p++!=0);
  1050.     }
  1051.     else
  1052.         Current_level_name[0]=0;
  1053.  
  1054.     if (game_top_fileinfo.fileinfo_version >= 19) { //load pof names
  1055.         N_save_pof_names = read_short(LoadFile);
  1056.         cfread(Save_pof_names,N_save_pof_names,13,LoadFile);
  1057.     }
  1058.  
  1059.     //===================== READ PLAYER INFO ==========================
  1060.     Object_next_signature = 0;
  1061.  
  1062.     //===================== READ OBJECT INFO ==========================
  1063.  
  1064.     Gamesave_num_org_robots = 0;
  1065.     Gamesave_num_players = 0;
  1066.  
  1067.     if (game_fileinfo.object_offset > -1) {
  1068.         if (cfseek( LoadFile, game_fileinfo.object_offset, SEEK_SET )) 
  1069.             Error( "Error seeking to object_offset in gamesave.c" );
  1070.     
  1071.         for (i=0;i<game_fileinfo.object_howmany;i++)    {
  1072.  
  1073.             read_object(&Objects[i],LoadFile,game_top_fileinfo.fileinfo_version);
  1074.  
  1075.             Objects[i].signature = Object_next_signature++;
  1076.             verify_object( &Objects[i] );
  1077.         }
  1078.  
  1079.     }
  1080.  
  1081.     //===================== READ WALL INFO ============================
  1082.  
  1083.     if (game_fileinfo.walls_offset > -1)
  1084.     {
  1085.  
  1086.         if (!cfseek( LoadFile, game_fileinfo.walls_offset,SEEK_SET ))   {
  1087.             for (i=0;i<game_fileinfo.walls_howmany;i++) {
  1088.  
  1089.                 if (game_top_fileinfo.fileinfo_version >= 20) {
  1090.  
  1091.                     Assert(sizeof(Walls[i]) == game_fileinfo.walls_sizeof);
  1092.  
  1093.                     Walls[i].segnum = read_int(LoadFile);
  1094.                     Walls[i].sidenum = read_int(LoadFile);
  1095.                     Walls[i].hps = read_fix(LoadFile);
  1096.                     Walls[i].linked_wall = read_int(LoadFile);
  1097.                     Walls[i].type = read_byte(LoadFile);
  1098.                     Walls[i].flags = read_byte(LoadFile);
  1099.                     Walls[i].state = read_byte(LoadFile);
  1100.                     Walls[i].trigger = read_byte(LoadFile);
  1101.                     Walls[i].clip_num = read_byte(LoadFile);
  1102.                     Walls[i].keys = read_byte(LoadFile);
  1103.                     Walls[i].pad = read_short(LoadFile);
  1104.  
  1105.  
  1106.                 }
  1107.                 else if (game_top_fileinfo.fileinfo_version >= 17) {
  1108.                     v19_wall w;
  1109.  
  1110.                     Assert(sizeof(w) == game_fileinfo.walls_sizeof);
  1111.  
  1112.                     if (cfread(&w, game_fileinfo.walls_sizeof, 1,LoadFile)!=1)
  1113.                         Error( "Error reading Walls[%d] in gamesave.c", i);
  1114.  
  1115.                     Walls[i].segnum         = swapint(w.segnum);
  1116.                     Walls[i].sidenum        = swapint(w.sidenum);
  1117.                     Walls[i].linked_wall    = swapint(w.linked_wall);
  1118.  
  1119.                     Walls[i].type           = w.type;
  1120.                     Walls[i].flags          = w.flags;
  1121.                     Walls[i].hps            = (fix)swapint(w.hps);
  1122.                     Walls[i].trigger        = w.trigger;
  1123.                     Walls[i].clip_num       = w.clip_num;
  1124.                     Walls[i].keys           = w.keys;
  1125.  
  1126.                     Walls[i].state          = WALL_DOOR_CLOSED;
  1127.                 }
  1128.                 else {
  1129.                     v16_wall w;
  1130.  
  1131.                     Assert(sizeof(w) == game_fileinfo.walls_sizeof);
  1132.  
  1133.                     if (cfread(&w, game_fileinfo.walls_sizeof, 1,LoadFile)!=1)
  1134.                         Error( "Error reading Walls[%d] in gamesave.c", i);
  1135.  
  1136.                     Walls[i].segnum = Walls[i].sidenum = Walls[i].linked_wall = -1;
  1137.  
  1138.                     Walls[i].type       = w.type;
  1139.                     Walls[i].flags      = w.flags;
  1140.                     Walls[i].hps        = (fix)swapint(w.hps);
  1141.                     Walls[i].trigger    = w.trigger;
  1142.                     Walls[i].clip_num   = w.clip_num;
  1143.                     Walls[i].keys       = w.keys;
  1144.                 }
  1145.  
  1146.             }
  1147.         }
  1148.     }
  1149.  
  1150.     //===================== READ DOOR INFO ============================
  1151.  
  1152.     if (game_fileinfo.doors_offset > -1)
  1153.     {
  1154.         if (!cfseek( LoadFile, game_fileinfo.doors_offset,SEEK_SET ))   {
  1155.  
  1156.             for (i=0;i<game_fileinfo.doors_howmany;i++) {
  1157.  
  1158.                 if (game_top_fileinfo.fileinfo_version >= 20) {
  1159.  
  1160.                     Assert(sizeof(ActiveDoors[i]) == game_fileinfo.doors_sizeof);
  1161.                     ActiveDoors[i].n_parts = read_int(LoadFile);
  1162.                     ActiveDoors[i].front_wallnum[0] = read_short(LoadFile);
  1163.                     ActiveDoors[i].front_wallnum[1] = read_short(LoadFile);
  1164.                     ActiveDoors[i].back_wallnum[0] = read_short(LoadFile);
  1165.                     ActiveDoors[i].back_wallnum[1] = read_short(LoadFile);
  1166.                     ActiveDoors[i].time = read_fix(LoadFile);
  1167.  
  1168.                 }
  1169.                 else {
  1170.                     v19_door d;
  1171.                     int p;
  1172.  
  1173.                     Assert(sizeof(d) == game_fileinfo.doors_sizeof);
  1174.  
  1175.                     if (cfread(&d, game_fileinfo.doors_sizeof, 1,LoadFile)!=1)
  1176.                         Error( "Error reading Doors[%d] in gamesave.c", i);
  1177.  
  1178.                     ActiveDoors[i].n_parts = swapint(d.n_parts);
  1179.  
  1180.                     for (p=0;p<d.n_parts;p++) {
  1181.                         int cseg,cside;
  1182.  
  1183.                         cseg = Segments[d.seg[p]].children[d.side[p]];
  1184.                         cside = find_connect_side(&Segments[d.seg[p]],&Segments[cseg]);
  1185.  
  1186.                         ActiveDoors[i].front_wallnum[p] = Segments[d.seg[p]].sides[d.side[p]].wall_num;
  1187.                         ActiveDoors[i].back_wallnum[p] = Segments[cseg].sides[cside].wall_num;
  1188.                     }
  1189.                 }
  1190.  
  1191.             }
  1192.         }
  1193.     }
  1194.  
  1195.     //==================== READ TRIGGER INFO ==========================
  1196.  
  1197.     if (game_fileinfo.triggers_offset > -1)     {
  1198.         if (!cfseek( LoadFile, game_fileinfo.triggers_offset,SEEK_SET ))    {
  1199.             for (i=0;i<game_fileinfo.triggers_howmany;i++)  {
  1200.                 //Assert( sizeof(Triggers[i]) == game_fileinfo.triggers_sizeof );
  1201.                 //if (cfread(&Triggers[i], game_fileinfo.triggers_sizeof,1,LoadFile)!=1)
  1202.                 //  Error( "Error reading Triggers[%d] in gamesave.c", i);
  1203.                 Triggers[i].type = read_byte(LoadFile);
  1204.                 Triggers[i].flags = read_short(LoadFile);
  1205.                 Triggers[i].value = read_int(LoadFile);
  1206.                 Triggers[i].time = read_int(LoadFile);
  1207.                 Triggers[i].link_num = read_byte(LoadFile);
  1208.                 Triggers[i].num_links = read_short(LoadFile);
  1209.                 for (j=0; j<MAX_WALLS_PER_LINK; j++ )   
  1210.                     Triggers[i].seg[j] = read_short(LoadFile);
  1211.                 for (j=0; j<MAX_WALLS_PER_LINK; j++ )
  1212.                     Triggers[i].side[j] = read_short(LoadFile);
  1213.             }
  1214.         }
  1215.     }
  1216.  
  1217.     //================ READ CONTROL CENTER TRIGGER INFO ===============
  1218.  
  1219.     if (game_fileinfo.control_offset > -1)
  1220.     {
  1221.         if (!cfseek( LoadFile, game_fileinfo.control_offset,SEEK_SET )) {
  1222.             for (i=0;i<game_fileinfo.control_howmany;i++) {
  1223.                 ControlCenterTriggers.num_links = read_short(LoadFile);
  1224.                 for (j=0; j<MAX_WALLS_PER_LINK; j++ )
  1225.                     ControlCenterTriggers.seg[j] = read_short( LoadFile );
  1226.                 for (j=0; j<MAX_WALLS_PER_LINK; j++ )
  1227.                     ControlCenterTriggers.side[j] = read_short( LoadFile );
  1228.             }
  1229.         }
  1230.     }
  1231.  
  1232.  
  1233.     //================ READ MATERIALOGRIFIZATIONATORS INFO ===============
  1234.  
  1235.     if (game_fileinfo.matcen_offset > -1)
  1236.     {   int j;
  1237.  
  1238.         if (!cfseek( LoadFile, game_fileinfo.matcen_offset,SEEK_SET ))  {
  1239.             // mprintf((0, "Reading %i materialization centers.\n", game_fileinfo.matcen_howmany));
  1240.             for (i=0;i<game_fileinfo.matcen_howmany;i++) {
  1241.                 RobotCenters[i].robot_flags = read_int_swap(LoadFile);
  1242.                 RobotCenters[i].hit_points = read_fix_swap(LoadFile);
  1243.                 RobotCenters[i].interval = read_fix_swap(LoadFile);
  1244.                 RobotCenters[i].segnum = read_short_swap(LoadFile);
  1245.                 RobotCenters[i].fuelcen_num = read_short_swap(LoadFile);
  1246.  
  1247.                 for (j=0; j<=Highest_segment_index; j++)
  1248.                     if (Segments[j].special == SEGMENT_IS_ROBOTMAKER)
  1249.                         if (Segments[j].matcen_num == i)
  1250.                             RobotCenters[i].fuelcen_num = Segments[j].value;
  1251.  
  1252.                 // mprintf((0, "   %i: flags = %08x\n", i, RobotCenters[i].robot_flags));
  1253.             }
  1254.         }
  1255.     }
  1256.  
  1257.  
  1258.     //========================= UPDATE VARIABLES ======================
  1259.  
  1260.     reset_objects(game_fileinfo.object_howmany);
  1261.  
  1262.     for (i=0; i<MAX_OBJECTS; i++) {
  1263.         Objects[i].next = Objects[i].prev = -1;
  1264.         if (Objects[i].type != OBJ_NONE) {
  1265.             int objsegnum = Objects[i].segnum;
  1266.  
  1267.             if (objsegnum > Highest_segment_index)      //bogus object
  1268.                 Objects[i].type = OBJ_NONE;
  1269.             else {
  1270.                 Objects[i].segnum = -1;         //avoid Assert()
  1271.                 obj_link(i,objsegnum);
  1272.             }
  1273.         }
  1274.     }
  1275.  
  1276.     clear_transient_objects(1);     //1 means clear proximity bombs
  1277.  
  1278.     // Make sure non-transparent doors are set correctly.
  1279.     for (i=0; i< Num_segments; i++)
  1280.         for (j=0;j<MAX_SIDES_PER_SEGMENT;j++) {
  1281.             side    *sidep = &Segments[i].sides[j];
  1282.             if ((sidep->wall_num != -1) && (Walls[sidep->wall_num].clip_num != -1)) {
  1283.                 //mprintf((0, "Checking Wall %d\n", Segments[i].sides[j].wall_num));
  1284.                 if (WallAnims[Walls[sidep->wall_num].clip_num].flags & WCF_TMAP1) {
  1285.                     //mprintf((0, "Fixing non-transparent door.\n"));
  1286.                     sidep->tmap_num = WallAnims[Walls[sidep->wall_num].clip_num].frames[0];
  1287.                     sidep->tmap_num2 = 0;
  1288.                 }
  1289.             }
  1290.         }
  1291.  
  1292.  
  1293.     Num_walls = game_fileinfo.walls_howmany;
  1294.     reset_walls();
  1295.  
  1296.     Num_open_doors = game_fileinfo.doors_howmany;
  1297.     Num_triggers = game_fileinfo.triggers_howmany;
  1298.  
  1299.     Num_robot_centers = game_fileinfo.matcen_howmany;
  1300.  
  1301.     //fix old wall structs
  1302.     if (game_top_fileinfo.fileinfo_version < 17) {
  1303.         int segnum,sidenum,wallnum;
  1304.  
  1305.         for (segnum=0; segnum<=Highest_segment_index; segnum++)
  1306.             for (sidenum=0;sidenum<6;sidenum++)
  1307.                 if ((wallnum=Segments[segnum].sides[sidenum].wall_num) != -1) {
  1308.                     Walls[wallnum].segnum = segnum;
  1309.                     Walls[wallnum].sidenum = sidenum;
  1310.                 }
  1311.     }
  1312.  
  1313.     #ifndef NDEBUG
  1314.     {
  1315.         int sidenum;
  1316.         for (sidenum=0; sidenum<6; sidenum++) {
  1317.             int wallnum = Segments[Highest_segment_index].sides[sidenum].wall_num;
  1318.             if (wallnum != -1)
  1319.                 if ((Walls[wallnum].segnum != Highest_segment_index) || (Walls[wallnum].sidenum != sidenum))
  1320.                     Int3(); //  Error.  Bogus walls in this segment.
  1321.                                 // Consult Yuan or Mike.
  1322.         }
  1323.     }
  1324.     #endif
  1325.  
  1326.     //create_local_segment_data();
  1327.  
  1328.     fix_object_segs();
  1329.  
  1330.     #ifndef NDEBUG
  1331.     dump_mine_info();
  1332.     #endif
  1333.  
  1334.     if (game_top_fileinfo.fileinfo_version < GAME_VERSION)
  1335.         return 1;       //means old version
  1336.     else
  1337.         return 0;
  1338. }
  1339.  
  1340.  
  1341. int check_segment_connections(void);
  1342.  
  1343. // -----------------------------------------------------------------------------
  1344. //loads from an already-open file
  1345. // returns 0=everything ok, 1=old version, -1=error
  1346. int load_mine_data(CFILE *LoadFile);
  1347. int load_mine_data_compiled(CFILE *LoadFile);
  1348.  
  1349. #define LEVEL_FILE_VERSION      1
  1350.  
  1351. #ifndef RELEASE
  1352. char *Level_being_loaded=NULL;
  1353. #endif
  1354.  
  1355. #ifdef COMPACT_SEGS
  1356. extern void ncache_flush();
  1357. #endif
  1358.  
  1359. //loads a level (.LVL) file from disk
  1360. int load_level(char * filename_passed)
  1361. {
  1362.     #ifdef EDITOR
  1363.     int use_compiled_level=1;
  1364.     #endif
  1365.     CFILE * LoadFile;
  1366.     char filename[128];
  1367.     int sig,version,minedata_offset,gamedata_offset,hostagetext_offset;
  1368.     int mine_err,game_err;
  1369.     int iii;
  1370.  
  1371.     #ifdef COMPACT_SEGS
  1372.     ncache_flush();
  1373.     #endif
  1374.  
  1375.     #ifndef RELEASE
  1376.     Level_being_loaded = filename_passed;
  1377.     #endif
  1378.  
  1379.     strcpy(filename,filename_passed);
  1380.  
  1381.     #ifdef EDITOR
  1382.     //check extension to see what file type this is
  1383.     for (iii = 0; iii < strlen(filename); iii++) {
  1384.         filename[iii] = (char)toupper(filename[iii]);
  1385.     }
  1386.  
  1387.     if (strstr(filename,".LVL"))
  1388.         use_compiled_level = 0;
  1389.         #ifdef SHAREWARE
  1390.     else if (!strstr(filename,".SDL")) {
  1391.         convert_name_to_CDL(filename,filename_passed);
  1392.         use_compiled_level = 1;
  1393.     }
  1394.         #else
  1395.     else if (!strstr(filename,".RDL")) {
  1396.         convert_name_to_CDL(filename,filename_passed);
  1397.         use_compiled_level = 1;
  1398.     }
  1399.         #endif
  1400.  
  1401.     // If we're trying to load a CDL, and we can't find it, and we have
  1402.     // the editor compiled in, then load the LVL.
  1403.     if ( (!cfexist(filename)) && use_compiled_level )   {
  1404.         convert_name_to_LVL(filename,filename_passed);
  1405.         use_compiled_level = 0;
  1406.     }       
  1407.     #endif
  1408.  
  1409.     LoadFile = cfopen( filename, "rb" );
  1410. //CF_READ_MODE );
  1411.  
  1412. #ifdef EDITOR
  1413.     if (!LoadFile)  {
  1414.         mprintf((0,"Can't open file <%s>\n", filename));
  1415.         return 1;
  1416.     }
  1417. #else
  1418.     if (!LoadFile)
  1419.         Error("Can't open file <%s>\n",filename);
  1420. #endif
  1421.  
  1422.     strcpy( Gamesave_current_filename, filename );
  1423.  
  1424. //  #ifdef NEWDEMO
  1425. //  if ( Newdemo_state == ND_STATE_RECORDING )
  1426. //      newdemo_record_start_demo();
  1427. //  #endif
  1428.  
  1429.     sig                     = read_int(LoadFile);
  1430.     version                 = read_int(LoadFile);
  1431.     minedata_offset     = read_int(LoadFile);
  1432.     gamedata_offset     = read_int(LoadFile);
  1433.     hostagetext_offset  = read_int(LoadFile);
  1434.  
  1435.     Assert(sig == 'PLVL');
  1436.  
  1437.     cfseek(LoadFile,minedata_offset,SEEK_SET);
  1438.     #ifdef EDITOR
  1439.     if (!use_compiled_level)
  1440.         mine_err = load_mine_data(LoadFile);
  1441.     else
  1442.     #endif
  1443.         //NOTE LINK TO ABOVE!!
  1444.         mine_err = load_mine_data_compiled(LoadFile);
  1445.  
  1446.     if (mine_err == -1) //error!!
  1447.         return 1;
  1448.  
  1449.     cfseek(LoadFile,gamedata_offset,SEEK_SET);
  1450.     game_err = load_game_data(LoadFile);
  1451.  
  1452.     if (game_err == -1) //error!!
  1453.         return 1;
  1454.  
  1455.     #ifdef HOSTAGE_FACES
  1456.     cfseek(LoadFile,hostagetext_offset,SEEK_SET);
  1457.     load_hostage_data(LoadFile,(version>=1));
  1458.     #endif
  1459.  
  1460.     //======================== CLOSE FILE =============================
  1461.  
  1462.     cfclose( LoadFile );
  1463.  
  1464.     #ifdef EDITOR
  1465.     write_game_text_file(filename);
  1466.     if (Errors_in_mine) {
  1467.         if (is_real_level(filename)) {
  1468.             char  ErrorMessage[200];
  1469.  
  1470.             sprintf( ErrorMessage, "Warning: %i errors in %s!\n", Errors_in_mine, Level_being_loaded );
  1471.             stop_time();
  1472.             gr_palette_load(gr_palette);
  1473.             nm_messagebox( NULL, 1, "Continue", ErrorMessage );
  1474.             start_time();
  1475.         } else
  1476.             mprintf((1, "Error: %i errors in %s.\n", Errors_in_mine, Level_being_loaded));
  1477.     }
  1478.     #endif
  1479.  
  1480.     #ifdef EDITOR
  1481.     //If an old version, ask the use if he wants to save as new version
  1482.     if (((LEVEL_FILE_VERSION>1) && version<LEVEL_FILE_VERSION) || mine_err==1 || game_err==1) {
  1483.         char  ErrorMessage[200];
  1484.  
  1485.         sprintf( ErrorMessage, "You just loaded a old version level.  Would\n"
  1486.                         "you like to save it as a current version level?");
  1487.  
  1488.         stop_time();
  1489.         gr_palette_load(gr_palette);
  1490.         if (nm_messagebox( NULL, 2, "Don't Save", "Save", ErrorMessage )==1)
  1491.             save_level(filename);
  1492.         start_time();
  1493.     }
  1494.     #endif
  1495.  
  1496.     #ifdef EDITOR
  1497.     if (Function_mode == FMODE_EDITOR)
  1498.         editor_status("Loaded NEW mine %s, \"%s\"",filename,Current_level_name);
  1499.     #endif
  1500.  
  1501.     #ifdef EDITOR
  1502.     if (check_segment_connections())
  1503.         nm_messagebox( "ERROR", 1, "Ok", 
  1504.                 "Connectivity errors detected in\n"
  1505.                 "mine.  See monochrome screen for\n"
  1506.                 "details, and contact Matt or Mike." );
  1507.     #endif
  1508.  
  1509.     return 0;
  1510. }
  1511.  
  1512. #ifdef EDITOR
  1513. void get_level_name()
  1514. {
  1515. //NO_UI!!!  UI_WINDOW               *NameWindow = NULL;
  1516. //NO_UI!!!  UI_GADGET_INPUTBOX  *NameText;
  1517. //NO_UI!!!  UI_GADGET_BUTTON        *QuitButton;
  1518. //NO_UI!!!
  1519. //NO_UI!!!  // Open a window with a quit button
  1520. //NO_UI!!!  NameWindow = ui_open_window( 20, 20, 300, 110, WIN_DIALOG );
  1521. //NO_UI!!!  QuitButton = ui_add_gadget_button( NameWindow, 150-24, 60, 48, 40, "Done", NULL );
  1522. //NO_UI!!!
  1523. //NO_UI!!!  ui_wprintf_at( NameWindow, 10, 12,"Please enter a name for this mine:" );
  1524. //NO_UI!!!  NameText = ui_add_gadget_inputbox( NameWindow, 10, 30, LEVEL_NAME_LEN, LEVEL_NAME_LEN, Current_level_name );
  1525. //NO_UI!!!
  1526. //NO_UI!!!  NameWindow->keyboard_focus_gadget = (UI_GADGET *)NameText;
  1527. //NO_UI!!!  QuitButton->hotkey = KEY_ENTER;
  1528. //NO_UI!!!
  1529. //NO_UI!!!  ui_gadget_calc_keys(NameWindow);
  1530. //NO_UI!!!
  1531. //NO_UI!!!  while (!QuitButton->pressed && last_keypress!=KEY_ENTER) {
  1532. //NO_UI!!!      ui_mega_process();
  1533. //NO_UI!!!      ui_window_do_gadgets(NameWindow);
  1534. //NO_UI!!!  }
  1535. //NO_UI!!!
  1536. //NO_UI!!!  strcpy( Current_level_name, NameText->text );
  1537. //NO_UI!!!
  1538. //NO_UI!!!  if ( NameWindow!=NULL ) {
  1539. //NO_UI!!!      ui_close_window( NameWindow );
  1540. //NO_UI!!!      NameWindow = NULL;
  1541. //NO_UI!!!  }
  1542. //NO_UI!!!
  1543.  
  1544.     newmenu_item m[2];
  1545.  
  1546.     m[0].type = NM_TYPE_TEXT; m[0].text = "Please enter a name for this mine:";
  1547.     m[1].type = NM_TYPE_INPUT; m[1].text = Current_level_name; m[1].text_len = LEVEL_NAME_LEN;
  1548.  
  1549.     newmenu_do( NULL, "Enter mine name", 2, m, NULL );
  1550.  
  1551. }
  1552. #endif
  1553.  
  1554.  
  1555. #ifdef EDITOR
  1556.  
  1557. int Errors_in_mine;
  1558.  
  1559. // -----------------------------------------------------------------------------
  1560. // Save game
  1561. int save_game_data(FILE * SaveFile)
  1562. {
  1563.     int  player_offset, object_offset, walls_offset, doors_offset, triggers_offset, control_offset, matcen_offset; //, links_offset;
  1564.     int start_offset,end_offset;
  1565.  
  1566.     start_offset = ftell(SaveFile);
  1567.  
  1568.     //===================== SAVE FILE INFO ========================
  1569.  
  1570.     game_fileinfo.fileinfo_signature =  0x6705;
  1571.     game_fileinfo.fileinfo_version  =   GAME_VERSION;
  1572.     game_fileinfo.level                 =  Current_level_num;
  1573.     game_fileinfo.fileinfo_sizeof       =   sizeof(game_fileinfo);
  1574.     game_fileinfo.player_offset     =   -1;
  1575.     game_fileinfo.player_sizeof     =   sizeof(player);
  1576.     game_fileinfo.object_offset     =   -1;
  1577.     game_fileinfo.object_howmany        =   Highest_object_index+1;
  1578.     game_fileinfo.object_sizeof     =   sizeof(object);
  1579.     game_fileinfo.walls_offset          =   -1;
  1580.     game_fileinfo.walls_howmany     =   Num_walls;
  1581.     game_fileinfo.walls_sizeof          =   sizeof(wall);
  1582.     game_fileinfo.doors_offset          =   -1;
  1583.     game_fileinfo.doors_howmany     =   Num_open_doors;
  1584.     game_fileinfo.doors_sizeof          =   sizeof(active_door);
  1585.     game_fileinfo.triggers_offset       =   -1;
  1586.     game_fileinfo.triggers_howmany  =   Num_triggers;
  1587.     game_fileinfo.triggers_sizeof       =   sizeof(trigger);
  1588.     game_fileinfo.control_offset        =   -1;
  1589.     game_fileinfo.control_howmany       =  1;
  1590.     game_fileinfo.control_sizeof        =  sizeof(control_center_triggers);
  1591.     game_fileinfo.matcen_offset     =   -1;
  1592.     game_fileinfo.matcen_howmany        =   Num_robot_centers;
  1593.     game_fileinfo.matcen_sizeof     =   sizeof(matcen_info);
  1594.  
  1595.     // Write the fileinfo
  1596.     fwrite( &game_fileinfo, sizeof(game_fileinfo), 1, SaveFile );
  1597.  
  1598.     // Write the mine name
  1599.     fprintf(SaveFile,Current_level_name);
  1600.     fputc(0,SaveFile);      //terminator for string
  1601.  
  1602.     fwrite(&N_save_pof_names,2,1,SaveFile);
  1603.     fwrite(Pof_names,N_polygon_models,13,SaveFile);
  1604.  
  1605.     //==================== SAVE PLAYER INFO ===========================
  1606.  
  1607.     player_offset = ftell(SaveFile);
  1608.     fwrite( &Players[Player_num], sizeof(player), 1, SaveFile );
  1609.  
  1610.     //==================== SAVE OBJECT INFO ===========================
  1611.  
  1612.     object_offset = ftell(SaveFile);
  1613.     //fwrite( &Objects, sizeof(object), game_fileinfo.object_howmany, SaveFile );
  1614.     {
  1615.         int i;
  1616.         for (i=0;i<game_fileinfo.object_howmany;i++)
  1617.             write_object(&Objects[i],SaveFile);
  1618.     }
  1619.  
  1620.     //==================== SAVE WALL INFO =============================
  1621.  
  1622.     walls_offset = ftell(SaveFile);
  1623.     fwrite( Walls, sizeof(wall), game_fileinfo.walls_howmany, SaveFile );
  1624.  
  1625.     //==================== SAVE DOOR INFO =============================
  1626.  
  1627.     doors_offset = ftell(SaveFile);
  1628.     fwrite( ActiveDoors, sizeof(active_door), game_fileinfo.doors_howmany, SaveFile );
  1629.  
  1630.     //==================== SAVE TRIGGER INFO =============================
  1631.  
  1632.     triggers_offset = ftell(SaveFile);
  1633.     fwrite( Triggers, sizeof(trigger), game_fileinfo.triggers_howmany, SaveFile );
  1634.  
  1635.     //================ SAVE CONTROL CENTER TRIGGER INFO ===============
  1636.  
  1637.     control_offset = ftell(SaveFile);
  1638.     fwrite( &ControlCenterTriggers, sizeof(control_center_triggers), 1, SaveFile );
  1639.  
  1640.  
  1641.     //================ SAVE MATERIALIZATION CENTER TRIGGER INFO ===============
  1642.  
  1643.     matcen_offset = ftell(SaveFile);
  1644.     // mprintf((0, "Writing %i materialization centers\n", game_fileinfo.matcen_howmany));
  1645.     // { int i;
  1646.     // for (i=0; i<game_fileinfo.matcen_howmany; i++)
  1647.     //  mprintf((0, "   %i: robot_flags = %08x\n", i, RobotCenters[i].robot_flags));
  1648.     // }
  1649.     fwrite( RobotCenters, sizeof(matcen_info), game_fileinfo.matcen_howmany, SaveFile );
  1650.  
  1651.     //============= REWRITE FILE INFO, TO SAVE OFFSETS ===============
  1652.  
  1653.     // Update the offset fields
  1654.     game_fileinfo.player_offset     =   player_offset;
  1655.     game_fileinfo.object_offset     =   object_offset;
  1656.     game_fileinfo.walls_offset          =   walls_offset;
  1657.     game_fileinfo.doors_offset          =   doors_offset;
  1658.     game_fileinfo.triggers_offset       =   triggers_offset;
  1659.     game_fileinfo.control_offset        =   control_offset;
  1660.     game_fileinfo.matcen_offset     =   matcen_offset;
  1661.  
  1662.  
  1663.     end_offset = ftell(SaveFile);
  1664.  
  1665.     // Write the fileinfo
  1666.     fseek(  SaveFile, start_offset, SEEK_SET );  // Move to TOF
  1667.     fwrite( &game_fileinfo, sizeof(game_fileinfo), 1, SaveFile );
  1668.  
  1669.     // Go back to end of data
  1670.     fseek(SaveFile,end_offset,SEEK_SET);
  1671.  
  1672.     return 0;
  1673. }
  1674.  
  1675. int save_mine_data(FILE * SaveFile);
  1676.  
  1677. // -----------------------------------------------------------------------------
  1678. // Save game
  1679. int save_level_sub(char * filename, int compiled_version)
  1680. {
  1681.     FILE * SaveFile;
  1682.     char temp_filename[128];
  1683.     int sig = 'PLVL',version=LEVEL_FILE_VERSION;
  1684.     int minedata_offset,gamedata_offset,hostagetext_offset;
  1685.  
  1686.     if ( !compiled_version )    {
  1687.         write_game_text_file(filename);
  1688.  
  1689.         if (Errors_in_mine) {
  1690.             if (is_real_level(filename)) {
  1691.                 char  ErrorMessage[200];
  1692.     
  1693.                 sprintf( ErrorMessage, "Warning: %i errors in this mine!\n", Errors_in_mine );
  1694.                 stop_time();
  1695.                 gr_palette_load(gr_palette);
  1696.      
  1697.                 if (nm_messagebox( NULL, 2, "Cancel Save", "Save", ErrorMessage )!=1)   {
  1698.                     start_time();
  1699.                     return 1;
  1700.                 }
  1701.                 start_time();
  1702.             } else
  1703.                 mprintf((1, "Error: %i errors in this mine.  See the 'txm' file.\n", Errors_in_mine));
  1704.         }
  1705.         convert_name_to_LVL(temp_filename,filename);
  1706.     } else {
  1707.         convert_name_to_CDL(temp_filename,filename);
  1708.     }
  1709.  
  1710.     SaveFile = fopen( temp_filename, "wb" );
  1711.     if (!SaveFile)
  1712.     {
  1713.         char ErrorMessage[256];
  1714.  
  1715.         char fname[20];
  1716. //        _splitpath( temp_filename, NULL, NULL, fname, NULL );
  1717.  
  1718.         sprintf( ErrorMessage, \
  1719.             "ERROR: Cannot write to '%s'.\n"
  1720.             , temp_filename, fname );
  1721.         stop_time();
  1722.         gr_palette_load(gr_palette);
  1723.         nm_messagebox( NULL, 1, "Ok", ErrorMessage );
  1724.         start_time();
  1725.         return 1;
  1726.     }
  1727.  
  1728.     if (Current_level_name[0] == 0)
  1729.         strcpy(Current_level_name,"Untitled");
  1730.  
  1731.     clear_transient_objects(1);     //1 means clear proximity bombs
  1732.  
  1733.     compress_objects();     //after this, Highest_object_index == num objects
  1734.  
  1735.     //make sure player is in a segment
  1736.     if (update_object_seg(&Objects[Players[0].objnum]) == 0) {
  1737.         if (ConsoleObject->segnum > Highest_segment_index)
  1738.             ConsoleObject->segnum = 0;
  1739.         compute_segment_center(&ConsoleObject->pos,&(Segments[ConsoleObject->segnum]));
  1740.     }
  1741.  
  1742.     fix_object_segs();
  1743.  
  1744.     //Write the header
  1745.  
  1746.     gs_write_int(sig,SaveFile);
  1747.     gs_write_int(version,SaveFile);
  1748.  
  1749.     //save placeholders
  1750.     gs_write_int(minedata_offset,SaveFile);
  1751.     gs_write_int(gamedata_offset,SaveFile);
  1752.     gs_write_int(hostagetext_offset,SaveFile);
  1753.  
  1754.     //Now write the damn data
  1755.  
  1756.     minedata_offset = ftell(SaveFile);
  1757.     if ( !compiled_version )    
  1758.         save_mine_data(SaveFile);
  1759.     else
  1760.         save_mine_data_compiled(SaveFile);
  1761.     gamedata_offset = ftell(SaveFile);
  1762.     save_game_data(SaveFile);
  1763.     hostagetext_offset = ftell(SaveFile);
  1764.  
  1765.     #ifdef HOSTAGE_FACES
  1766.     save_hostage_data(SaveFile);
  1767.     #endif
  1768.  
  1769.     fseek(SaveFile,sizeof(sig)+sizeof(version),SEEK_SET);
  1770.     gs_write_int(minedata_offset,SaveFile);
  1771.     gs_write_int(gamedata_offset,SaveFile);
  1772.     gs_write_int(hostagetext_offset,SaveFile);
  1773.  
  1774.     //==================== CLOSE THE FILE =============================
  1775.     fclose(SaveFile);
  1776.  
  1777.     if ( !compiled_version )    {
  1778.         if (Function_mode == FMODE_EDITOR)
  1779.             editor_status("Saved mine %s, \"%s\"",filename,Current_level_name);
  1780.     }
  1781.  
  1782.     return 0;
  1783.  
  1784. }
  1785.  
  1786. int save_level(char * filename)
  1787. {
  1788.     int r1;
  1789.  
  1790.     // Save normal version...
  1791.     r1 = save_level_sub(filename, 0);
  1792.  
  1793.     // Save compiled version...
  1794.     save_level_sub(filename, 1);
  1795.  
  1796.     return r1;
  1797. }
  1798.  
  1799.  
  1800. #ifdef HOSTAGE_FACES
  1801. void save_hostage_data(FILE * fp)
  1802. {
  1803.     int i,num_hostages=0;
  1804.  
  1805.     // Find number of hostages in mine...
  1806.     for (i=0; i<=Highest_object_index; i++ )    {
  1807.         int num;
  1808.         if ( Objects[i].type == OBJ_HOSTAGE )   {
  1809.             num = Objects[i].id;
  1810.             if (UseShareware) {
  1811.                 if (num<0 || num>=MAX_HOSTAGES || Hostage_face_clip[Hostages[num].vclip_num].num_frames<=0)
  1812.                     num=0;
  1813.             } else
  1814.             num = 0;
  1815.  
  1816.             if (num+1 > num_hostages)
  1817.                 num_hostages = num+1;
  1818.         }
  1819.     }
  1820.  
  1821.     gs_write_int(HOSTAGE_DATA_VERSION,fp);
  1822.  
  1823.     for (i=0; i<num_hostages; i++ ) {
  1824.         gs_write_int(Hostages[i].vclip_num,fp);
  1825.         fputs(Hostages[i].text,fp);
  1826.         fputc('\n',fp);     //fgets wants a newline
  1827.     }
  1828. }
  1829. #endif  //HOSTAGE_FACES
  1830.  
  1831. #endif  //EDITOR
  1832.  
  1833. #ifndef NDEBUG
  1834. void dump_mine_info(void)
  1835. {
  1836.     int segnum, sidenum;
  1837.     fix min_u, max_u, min_v, max_v, min_l, max_l, max_sl;
  1838.  
  1839.     min_u = F1_0*1000;
  1840.     min_v = min_u;
  1841.     min_l = min_u;
  1842.  
  1843.     max_u = -min_u;
  1844.     max_v = max_u;
  1845.     max_l = max_u;
  1846.  
  1847.     max_sl = 0;
  1848.  
  1849.     for (segnum=0; segnum<=Highest_segment_index; segnum++) {
  1850.         for (sidenum=0; sidenum<MAX_SIDES_PER_SEGMENT; sidenum++) {
  1851.             int vertnum;
  1852.             side    *sidep = &Segments[segnum].sides[sidenum];
  1853.  
  1854.             if (Segments[segnum].static_light > max_sl)
  1855.                 max_sl = Segments[segnum].static_light;
  1856.  
  1857.             for (vertnum=0; vertnum<4; vertnum++) {
  1858.                 if (sidep->uvls[vertnum].u < min_u)
  1859.                     min_u = sidep->uvls[vertnum].u;
  1860.                 else if (sidep->uvls[vertnum].u > max_u)
  1861.                     max_u = sidep->uvls[vertnum].u;
  1862.  
  1863.                 if (sidep->uvls[vertnum].v < min_v)
  1864.                     min_v = sidep->uvls[vertnum].v;
  1865.                 else if (sidep->uvls[vertnum].v > max_v)
  1866.                     max_v = sidep->uvls[vertnum].v;
  1867.  
  1868.                 if (sidep->uvls[vertnum].l < min_l)
  1869.                     min_l = sidep->uvls[vertnum].l;
  1870.                 else if (sidep->uvls[vertnum].l > max_l)
  1871.                     max_l = sidep->uvls[vertnum].l;
  1872.             }
  1873.  
  1874.         }
  1875.     }
  1876.  
  1877. //  mprintf((0, "Smallest uvl = %7.3f %7.3f %7.3f.  Largest uvl = %7.3f %7.3f %7.3f\n", f2fl(min_u), f2fl(min_v), f2fl(min_l), f2fl(max_u), f2fl(max_v), f2fl(max_l)));
  1878. //  mprintf((0, "Static light maximum = %7.3f\n", f2fl(max_sl)));
  1879. //  mprintf((0, "Number of walls: %i\n", Num_walls));
  1880.  
  1881. }
  1882.  
  1883. #endif
  1884.  
  1885. #ifdef HOSTAGE_FACES
  1886. void load_hostage_data(CFILE * fp,int do_read)
  1887. {
  1888.     int version,i,num,num_hostages;
  1889.  
  1890.     hostage_init_all();
  1891.  
  1892.     num_hostages = 0;
  1893.  
  1894.     // Find number of hostages in mine...
  1895.     for (i=0; i<=Highest_object_index; i++ )    {
  1896.         if ( Objects[i].type == OBJ_HOSTAGE )   {
  1897.             num = Objects[i].id;
  1898.             if (num+1 > num_hostages)
  1899.                 num_hostages = num+1;
  1900.  
  1901.             if (Hostages[num].objnum != -1) {       //slot already used
  1902.                 num = hostage_get_next_slot();      //..so get new slot
  1903.                 if (num+1 > num_hostages)
  1904.                     num_hostages = num+1;
  1905.                 Objects[i].id = num;
  1906.             }
  1907.  
  1908.             if ( num > -1 && num < MAX_HOSTAGES )   {
  1909.                 Assert(Hostages[num].objnum == -1);     //make sure not used
  1910.                 // -- Matt -- commented out by MK on 11/19/94, hit often in level 3, level 4.  Assert(Hostages[num].objnum == -1);      //make sure not used
  1911.                 Hostages[num].objnum = i;
  1912.                 Hostages[num].objsig = Objects[i].signature;
  1913.             }
  1914.         }
  1915.     }
  1916.  
  1917.     if (do_read) {
  1918.         version = read_int(fp);
  1919.  
  1920.         for (i=0;i<num_hostages;i++) {
  1921.  
  1922.             Assert(Hostages[i].objnum != -1);       //make sure slot filled in
  1923.  
  1924.             Hostages[i].vclip_num = read_int(fp);
  1925.  
  1926.             if (UseShareware) {
  1927.                 if (Hostages[i].vclip_num<0 || Hostages[i].vclip_num>=MAX_HOSTAGES || Hostage_face_clip[Hostages[i].vclip_num].num_frames<=0)
  1928.                     Hostages[i].vclip_num=0;
  1929.  
  1930.                 Assert(Hostage_face_clip[Hostages[i].vclip_num].num_frames);
  1931.             }
  1932.  
  1933.             cfgets(Hostages[i].text, HOSTAGE_MESSAGE_LEN, fp);
  1934.  
  1935.             if (Hostages[i].text[strlen(Hostages[i].text)-1]=='\n')
  1936.                 Hostages[i].text[strlen(Hostages[i].text)-1] = 0;
  1937.         }
  1938.     }
  1939.     else
  1940.         for (i=0;i<num_hostages;i++) {
  1941.             Assert(Hostages[i].objnum != -1);       //make sure slot filled in
  1942.             Hostages[i].vclip_num = 0;
  1943.         }
  1944.  
  1945. }
  1946. #endif  //HOSTAGE_FACES
  1947.  
  1948.